package com.ruoyi.caipiao.service.impl;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.caipiao.domain.CaipiaoPl5History;
import com.ruoyi.caipiao.dto.req.GeneratePl5Req;
import com.ruoyi.caipiao.service.ICaipiaoPl5HistoryService;
import com.ruoyi.caipiao.utils.Pl5NumUtil;
import com.ruoyi.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.caipiao.mapper.CaipiaoPl5Mapper;
import com.ruoyi.caipiao.domain.CaipiaoPl5;
import com.ruoyi.caipiao.service.ICaipiaoPl5Service;

/**
 * 排列5计算Service业务层处理
 *
 * @author ruoyi
 * @date 2025-03-01
 */
@Slf4j
@Service
public class CaipiaoPl5ServiceImpl extends ServiceImpl<CaipiaoPl5Mapper, CaipiaoPl5> implements ICaipiaoPl5Service {
    @Autowired
    private CaipiaoPl5Mapper caipiaoPl5Mapper;

    @Autowired
    private ICaipiaoPl5HistoryService iCaipiaoPl5HistoryService;

    @Override
    public String getKjNum(String qs) {
        CaipiaoPl5History caipiaoPl5History = iCaipiaoPl5HistoryService.selectCaipiaoPl5HistoryByQs(Long.parseLong(qs));
        if (caipiaoPl5History == null) {
            return "";
        }
        return caipiaoPl5History.getKjNum();
    }

    @Override
    public void addPl5Num(GeneratePl5Req generatePl5Req) {
        CaipiaoPl5 caipiaoPl5 = new CaipiaoPl5();
        BeanUtil.copyProperties(generatePl5Req, caipiaoPl5);
        caipiaoPl5.setId(IdUtil.getSnowflakeNextId());
        caipiaoPl5Mapper.insertCaipiaoPl5(caipiaoPl5);
    }

    @Override
    public String generateNumMethod1(GeneratePl5Req generatePl5Req) {

        //预测期数
        DateTime cur = DateUtil.parse(generatePl5Req.getQs(), "yyyyMMdd");
        if (cur.isAfter(new Date())) {
            throw new RuntimeException("预测期数不能大于当前日期");
        }

        //获取前一天
        String yd = DateUtil.format(DateUtil.offsetDay(cur, -ThreadLocalRandom.current().nextInt(1, 7000)), "yyyyMMdd");

        CaipiaoPl5History caipiaoPl5History = iCaipiaoPl5HistoryService.selectCaipiaoPl5HistoryByQs(Long.parseLong(yd));
        String kjNum = caipiaoPl5History.getKjNum();
        return kjNum.substring(generatePl5Req.getPosition(), generatePl5Req.getPosition() + 1);
    }

    @Override
    public String generateNumMethod2(GeneratePl5Req generatePl5Req) {
        int size = ThreadLocalRandom.current().nextInt(200) + 750;
        log.info("generateNumMethod2 size:{}", size);
        Set<String> nums = Pl5NumUtil.getNums(size);
        for (; ; ) {
            nums.retainAll(Pl5NumUtil.getNums(size));
            if (nums.size() == 2) {
                log.info("得到一注号码：{}", nums);
                ArrayList<String> sets = new ArrayList<>(nums);
                String pn0 = sets.get(0).substring(generatePl5Req.getPosition(), generatePl5Req.getPosition() + 1);
                boolean same = true;
                for (String set : sets) {
                    if (!pn0.equals(set.substring(generatePl5Req.getPosition(), generatePl5Req.getPosition() + 1))) {
                        same = false;
                    }
                }
                if (same) {
                    return pn0;
                } else {
                    nums = Pl5NumUtil.getNums(800);
                }
            } else if (nums.isEmpty()) {
                nums = Pl5NumUtil.getNums(800);
            }
        }
    }

    @Override
    public String generateNumMethod3(GeneratePl5Req generatePl5Req) {
        for (; ; ) {
            int size = ThreadLocalRandom.current().nextInt(250) * 20 + 100;
            generatePl5Req.setSize(size);
            log.info("generateNumMethod3 size:{}", size);

            if (generatePl5Req.getSize() == 0 || generatePl5Req.getSize() % 2 != 0) {
                throw new RuntimeException("统计期数只能是偶数且大于0");
            }

            //预测期数
            DateTime cur = DateUtil.parse(generatePl5Req.getQs(), "yyyyMMdd");
            if (cur.isAfter(new Date())) {
                throw new RuntimeException("预测期数不能大于当前日期");
            }

            //获取前一天
            String yd = DateUtil.format(DateUtil.offsetDay(cur, -ThreadLocalRandom.current().nextInt(1, 7000)), "yyyyMMdd");

            List<String> newList = iCaipiaoPl5HistoryService.list(Long.parseLong(yd), generatePl5Req.getSize());
            String newKjCode = newList.get(0);
            String code0 = newKjCode.substring(0, 1);
            String code1 = newKjCode.substring(1, 2);
            String code2 = newKjCode.substring(2, 3);
            String code3 = newKjCode.substring(3, 4);
            String code4 = newKjCode.substring(4, 5);

            Map<String, Integer> mapP0 = new TreeMap<>();
            Map<String, Integer> mapP1 = new TreeMap<>();
            Map<String, Integer> mapP2 = new TreeMap<>();
            Map<String, Integer> mapP3 = new TreeMap<>();
            Map<String, Integer> mapP4 = new TreeMap<>();
            for (int i = newList.size() - 1; i > 0; i = i - 2) {
                String preNum = newList.get(i);  //上一个号码
                String kcNum = newList.get(i - 1);   //紧接着开出的号码
                putNumCount(mapP0, 0, preNum, kcNum);
                putNumCount(mapP1, 1, preNum, kcNum);
                putNumCount(mapP2, 2, preNum, kcNum);
                putNumCount(mapP3, 3, preNum, kcNum);
                putNumCount(mapP4, 4, preNum, kcNum);
            }

            Map<String, Integer> mapP = new TreeMap<>();

            if (generatePl5Req.getPosition() == 0) {
                log.info("------p0------------------");
                for (Map.Entry<String, Integer> entry : mapP0.entrySet()) {
                    if (entry.getKey().startsWith(code0)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (generatePl5Req.getPosition() == 1) {
                log.info("------p1------------------");
                for (Map.Entry<String, Integer> entry : mapP1.entrySet()) {
                    if (entry.getKey().startsWith(code1)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (generatePl5Req.getPosition() == 2) {
                log.info("------p2------------------");
                for (Map.Entry<String, Integer> entry : mapP2.entrySet()) {
                    if (entry.getKey().startsWith(code2)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (generatePl5Req.getPosition() == 3) {
                log.info("------p3------------------");
                for (Map.Entry<String, Integer> entry : mapP3.entrySet()) {
                    if (entry.getKey().startsWith(code3)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (generatePl5Req.getPosition() == 4) {
                log.info("------p4------------------");
                for (Map.Entry<String, Integer> entry : mapP4.entrySet()) {
                    if (entry.getKey().startsWith(code4)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            }

            log.info("结果：");
            for (Map.Entry<String, Integer> entry : mapP.entrySet()) {
                log.info(entry.getKey() + " : " + entry.getValue());
            }
            ArrayList<Map.Entry<String, Integer>> sortedList = new ArrayList<>(mapP.entrySet());
            sortedList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));

            String key = sortedList.get(0).getKey();
            String key1 = sortedList.get(1).getKey();
            if (mapP.get(key).intValue() == mapP.get(key1).intValue()) {
                continue;
            }
            return key;
        }
    }

    /**
     * 统计某一位置，开出某号码后，下一次开出另一号码的次数
     * 比如位置0， 上一次开出 8， 下一次开出 9， 则记录 89的次数+1；
     *
     * @param map
     * @param i      比如位置0
     * @param preNum 上一次开出 8
     * @param kcNum  下一次开出 9
     */
    private void putNumCount(Map<String, Integer> map, Integer i, String preNum, String kcNum) {
        String p0 = preNum.substring(i, i + 1);
        String k0 = kcNum.substring(i, i + 1);
        map.merge(p0 + "-" + k0, 1, Integer::sum);
    }

    @Override
    public String generateNumMethod4(GeneratePl5Req generatePl5Req) {
        for (; ; ) {
            int size;
            for (; ; ) {
                size = ThreadLocalRandom.current().nextInt(250) * 10 + 100;
                if (size % 3 == 0) {
                    break;
                }
            }
            generatePl5Req.setSize(size);
            log.info("generateNumMethod4 size:{}", size);
            if (generatePl5Req.getSize() == 0 || generatePl5Req.getSize() % 3 != 0) {
                throw new RuntimeException("统计期数只能是3的倍数且大于0");
            }

            //预测期数
            DateTime cur = DateUtil.parse(generatePl5Req.getQs(), "yyyyMMdd");
            if (cur.isAfter(new Date())) {
                throw new RuntimeException("预测期数不能大于当前日期");
            }

            //获取前一天
            String yd = DateUtil.format(DateUtil.offsetDay(cur, -ThreadLocalRandom.current().nextInt(1, 7000)), "yyyyMMdd");

            List<String> newList = iCaipiaoPl5HistoryService.list(Long.parseLong(yd), generatePl5Req.getSize());
            String newKjCode0 = newList.get(0);
            String code00 = newKjCode0.substring(0, 1);
            String code01 = newKjCode0.substring(1, 2);
            String code02 = newKjCode0.substring(2, 3);
            String code03 = newKjCode0.substring(3, 4);
            String code04 = newKjCode0.substring(4, 5);

            String newKjCode1 = newList.get(1);
            String code10 = newKjCode1.substring(0, 1);
            String code11 = newKjCode1.substring(1, 2);
            String code12 = newKjCode1.substring(2, 3);
            String code13 = newKjCode1.substring(3, 4);
            String code14 = newKjCode1.substring(4, 5);

            String sum0 = new BigDecimal(code00).subtract(new BigDecimal(code10)).abs().toString();
            String sum1 = new BigDecimal(code01).subtract(new BigDecimal(code11)).abs().toString();
            String sum2 = new BigDecimal(code02).subtract(new BigDecimal(code12)).abs().toString();
            String sum3 = new BigDecimal(code03).subtract(new BigDecimal(code13)).abs().toString();
            String sum4 = new BigDecimal(code04).subtract(new BigDecimal(code14)).abs().toString();

            Map<String, Integer> mapP0 = new TreeMap<>();
            Map<String, Integer> mapP1 = new TreeMap<>();
            Map<String, Integer> mapP2 = new TreeMap<>();
            Map<String, Integer> mapP3 = new TreeMap<>();
            Map<String, Integer> mapP4 = new TreeMap<>();
            for (int i = newList.size() - 1; i > 1; i = i - 3) {
                String preNum0 = newList.get(i);  //上一期的号码
                String preNum1 = newList.get(i - 1);  //上两期的号码
                String kcNum = newList.get(i - 2);   //紧接着开出的号码

                putSubNumCount(mapP0, 0, preNum0, preNum1, kcNum);
                putSubNumCount(mapP1, 1, preNum0, preNum1, kcNum);
                putSubNumCount(mapP2, 2, preNum0, preNum1, kcNum);
                putSubNumCount(mapP3, 3, preNum0, preNum1, kcNum);
                putSubNumCount(mapP4, 4, preNum0, preNum1, kcNum);
            }
            Map<String, Integer> mapP = new TreeMap<>();
            if (0 == generatePl5Req.getPosition()) {
                log.info("------p0------------------");
                for (Map.Entry<String, Integer> entry : mapP0.entrySet()) {
                    if (entry.getKey().startsWith(sum0)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (1 == generatePl5Req.getPosition()) {
                log.info("------p1------------------");
                for (Map.Entry<String, Integer> entry : mapP1.entrySet()) {
                    if (entry.getKey().startsWith(sum1)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (2 == generatePl5Req.getPosition()) {
                log.info("------p2------------------");
                for (Map.Entry<String, Integer> entry : mapP2.entrySet()) {
                    if (entry.getKey().startsWith(sum2)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else if (3 == generatePl5Req.getPosition()) {
                log.info("------p3------------------");
                for (Map.Entry<String, Integer> entry : mapP3.entrySet()) {
                    if (entry.getKey().startsWith(sum3)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            } else {
                log.info("------p4------------------");
                for (Map.Entry<String, Integer> entry : mapP4.entrySet()) {
                    if (entry.getKey().startsWith(sum4)) {
                        log.info(entry.getKey() + " : " + entry.getValue());
                        mapP.put(entry.getKey().substring(2), entry.getValue());
                    }
                }
            }

            log.info("结果：");
            for (Map.Entry<String, Integer> entry : mapP.entrySet()) {
                log.info(entry.getKey() + " : " + entry.getValue());
            }
            ArrayList<Map.Entry<String, Integer>> sortedList = new ArrayList<>(mapP.entrySet());
            sortedList.sort(Map.Entry.comparingByValue(Comparator.reverseOrder()));

            String key = sortedList.get(0).getKey();
            String key1 = sortedList.get(1).getKey();
            if (mapP.get(key).intValue() == mapP.get(key1).intValue()) {
                continue;
            }
            return key;
        }
    }

    private void putSubNumCount(Map<String, Integer> map, int i, String preNum0, String preNum1, String kcNum) {
        String p0 = preNum0.substring(i, i + 1);
        String p1 = preNum1.substring(i, i + 1);
        String sum = new BigDecimal(p0).subtract(new BigDecimal(p1)).abs().toString();

        String k0 = kcNum.substring(i, i + 1);
        map.merge(sum + "-" + k0, 1, Integer::sum);
    }

    @Override
    public String generateNumMethod5(GeneratePl5Req generatePl5Req) {
        for (; ; ) {
            int retainSize = ThreadLocalRandom.current().nextInt(0, 5) + 5;
            int size = 3 * retainSize;
            log.info("generateNumMethod5 size:" + size);
            generatePl5Req.setSize(size);
            //预测期数
            DateTime cur = DateUtil.parse(generatePl5Req.getQs(), "yyyyMMdd");
            if (cur.isAfter(new Date())) {
                throw new RuntimeException("预测期数不能大于当前日期");
            }

            //获取前一天
            String yd = DateUtil.format(DateUtil.offsetDay(cur, -ThreadLocalRandom.current().nextInt(1, 7000)), "yyyyMMdd");
            List<String> newList = iCaipiaoPl5HistoryService.list(Long.parseLong(yd), generatePl5Req.getSize());
            if (0 == generatePl5Req.getPosition()) {
                Set<String> p0Set_1 = getPositionSet(newList, 0, 0, retainSize);
                Set<String> p0Set_2 = getPositionSet(newList, 1, 0, retainSize);
                Set<String> p0Set_3 = getPositionSet(newList, 2, 0, retainSize);
                p0Set_1.retainAll(p0Set_2);
                p0Set_1.retainAll(p0Set_3);
                log.info("p0Set = " + p0Set_1);
                if (p0Set_1.size() == 1) {
                    return p0Set_1.iterator().next();
                }
            } else if (1 == generatePl5Req.getPosition()) {

                Set<String> p1Set_1 = getPositionSet(newList, 0, 1, retainSize);
                Set<String> p1Set_2 = getPositionSet(newList, 1, 1, retainSize);
                Set<String> p1Set_3 = getPositionSet(newList, 2, 1, retainSize);
                p1Set_1.retainAll(p1Set_2);
                p1Set_1.retainAll(p1Set_3);
                log.info("p1Set = " + p1Set_1);
                if (p1Set_1.size() == 1) {
                    return p1Set_1.iterator().next();
                }
            } else {

                Set<String> p2Set_1 = getPositionSet(newList, 0, 2, retainSize);
                Set<String> p2Set_2 = getPositionSet(newList, 1, 2, retainSize);
                Set<String> p2Set_3 = getPositionSet(newList, 2, 2, retainSize);
                p2Set_1.retainAll(p2Set_2);
                p2Set_1.retainAll(p2Set_3);
                log.info("p2Set = " + p2Set_1);
                if (p2Set_1.size() == 1) {
                    return p2Set_1.iterator().next();
                }
            }
        }
    }

    private Set<String> getPositionSet(List<String> list, int index, int position, int retainSize) {
        Set<String> set = new TreeSet<>();
        int start = index * retainSize;
        int end = (index + 1) * retainSize;
        for (int i = start; i < end; i++) {
            String code = list.get(i);
            set.add(code.substring(position, position + 1));
        }
        return set;
    }

    @Override
    public String generateNumMethod6(GeneratePl5Req generatePl5Req) {

        int cc = ThreadLocalRandom.current().nextInt(10000000) + 1000000; //计算次数
        log.info("cc：" + cc);

        Set<String> nums2 = new HashSet<>();
        int i = 0;
        for (; ; ) {
            String num = Pl5NumUtil.getNum();
            if (i > cc) {
                nums2.add(num);
                if (nums2.size() == generatePl5Req.getSize()) {
                    break;
                }
            }
            i++;
        }
        log.info("计算次数：" + i);
        Map<String, Integer> p0MapCt = new HashMap<>();
        Map<String, Integer> p1MapCt = new HashMap<>();
        Map<String, Integer> p2MapCt = new HashMap<>();
        for (String num : nums2) {
            String p0 = num.substring(0, 1);
            String p1 = num.substring(1, 2);
            String p2 = num.substring(2, 3);
            p0MapCt.merge(p0, 1, Integer::sum);
            p1MapCt.merge(p1, 1, Integer::sum);
            p2MapCt.merge(p2, 1, Integer::sum);
        }
        if (generatePl5Req.getPosition() == 0) {
            return p0MapCt.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
        } else if (generatePl5Req.getPosition() == 1) {
            return p1MapCt.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
        } else if (generatePl5Req.getPosition() == 2) {
            return p2MapCt.entrySet().stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey).orElse(null);
        }
        return null;
    }

    /**
     * 查询排列5计算
     *
     * @param id 排列5计算主键
     * @return 排列5计算
     */
    @Override
    public CaipiaoPl5 selectCaipiaoPl5ById(Long id) {
        return caipiaoPl5Mapper.selectCaipiaoPl5ById(id);
    }

    /**
     * 查询排列5计算列表
     *
     * @param caipiaoPl5 排列5计算
     * @return 排列5计算
     */
    @Override
    public List<CaipiaoPl5> selectCaipiaoPl5List(CaipiaoPl5 caipiaoPl5) {
        return caipiaoPl5Mapper.selectCaipiaoPl5List(caipiaoPl5);
    }

    /**
     * 新增排列5计算
     *
     * @param caipiaoPl5 排列5计算
     * @return 结果
     */
    @Override
    public int insertCaipiaoPl5(CaipiaoPl5 caipiaoPl5) {
        caipiaoPl5.setCreateTime(DateUtils.getNowDate());
        return caipiaoPl5Mapper.insertCaipiaoPl5(caipiaoPl5);
    }

    /**
     * 修改排列5计算
     *
     * @param caipiaoPl5 排列5计算
     * @return 结果
     */
    @Override
    public int updateCaipiaoPl5(CaipiaoPl5 caipiaoPl5) {
        return caipiaoPl5Mapper.updateCaipiaoPl5(caipiaoPl5);
    }

    /**
     * 批量删除排列5计算
     *
     * @param ids 需要删除的排列5计算主键
     * @return 结果
     */
    @Override
    public int deleteCaipiaoPl5ByIds(Long[] ids) {
        return caipiaoPl5Mapper.deleteCaipiaoPl5ByIds(ids);
    }

    /**
     * 删除排列5计算信息
     *
     * @param id 排列5计算主键
     * @return 结果
     */
    @Override
    public int deleteCaipiaoPl5ById(Long id) {
        return caipiaoPl5Mapper.deleteCaipiaoPl5ById(id);
    }
}
